/*
 * @description: 登录/授权
 * @Author: Islands
 * @Date: 2024-06-14 18:03:54
 * @LastEditTime: 2024-06-20 21:38:08
 */
import { defineStore } from 'pinia';
import { doLogin, doToken, doUserinfo, doRoutes, doLogout } from '@/api/service/login';
import { ILoginData, IUserInfo, IRoutes, IMeta, ILoginResult } from '@/api/types/login.d';
import { GlobalEnum } from '@/enums/index';
import Router from "@/layouts/Router/index.vue";
import { ElMessage } from 'element-plus'
import { IResult } from '@/api/types';
import { cookieCache, localCache, sessionCache } from '@/utils/cache/index';


//自动导入views目录下的所有.vue文件
const modules = import.meta.glob('/src/views/**/**.vue');

export const useStore = defineStore('authorize', {
    state: () => {
        return {
            userInfo: {} as IUserInfo,
            menuList: [] as any
        }
    },
    getters: {

    },
    actions: {
        async loginIn(loginData: ILoginData) {
            let { flag, message, data, code }: IResult<ILoginResult> = await doLogin(loginData);
            if (flag) {
                sessionStorage.setItem(GlobalEnum.AUTHORIZE, data.accessToken);
                ElMessage.success({ message })
                return data;
            }
            ElMessage.error({ message });
        },
        async getToken() {
            let { flag, message, data, code }: IResult<ILoginResult> = await doToken();
            if (flag) {
                sessionStorage.setItem(GlobalEnum.AUTHORIZE, data.accessToken);
                return data.accessToken;
            }
            ElMessage.error({ message });
        },
        async getUserInfo() {
            let result: any = await doUserinfo();
            if (result.flag) {
                return Object.assign(this.userInfo, result.data);
            }
            return;
        },
        async getRoutes(roles: Array<string>) {
            let result: any = await doRoutes();
            if (result.flag) {
                //根据角色判断
                const accessedRoutes = filterAsyncRoutes(result.data, roles);
                return Object.assign(this.menuList, { ...accessedRoutes });
            }
            return;

        },
        async removeToken() {
            let { flag, code, message }: IResult<null> = await doLogout();
            if (flag) {
                localCache.clear();
                sessionCache.clear();
                cookieCache.remove("UID");
                ElMessage.success(message);
                return flag;
            }
            ElMessage.warning(message);
            return flag;
        }
    },
});




/**
 * 递归过滤有权限的异步(动态)路由
 * @param routes    接口返回的异步(动态)路由
 * @param roles 用户角色集合
 * @returns 返回用户有权限的异步(动态)路由
 */
function filterAsyncRoutes(routes: Array<IRoutes<IMeta>>, roles: Array<string>) {
    const asyncRoutes: Array<IRoutes<IMeta>> = [];
    routes.forEach((route: IRoutes<IMeta>) => {
        const tmpRoute = { ...route }; // ES6扩展运算符复制新对象
        if (!route.name) {
            tmpRoute.name = route.path;
        }
        // 判断用户(角色)是否有该路由的访问权限
        if (hasPermission(roles, tmpRoute)) {
            if (tmpRoute.component === null || tmpRoute.component === undefined) {
                tmpRoute.component = Router;
            } else {
                const component = modules[`/src/views/${tmpRoute.component}/index.vue`];
                component ? tmpRoute.component = component :
                    tmpRoute.component = modules[`/src/views/404/index.vue`];
            }
            if (tmpRoute.children) {
                tmpRoute.children = filterAsyncRoutes(tmpRoute.children, roles);
            }
            asyncRoutes.push(tmpRoute);
        }

    });
    return asyncRoutes;
}

/**
 * 使用meta.role确定当前用户是否具有权限
 * @param roles 用户角色集合
 * @param route 路由
 * @returns
 */
const hasPermission = (roles: string[], route: IRoutes<IMeta>) => {
    if (route.meta && route.meta.roles) {
        // 角色【超级管理员】拥有所有权限，忽略校验
        if (roles.includes("root")) {
            return true;
        }
        return roles.some((role) => {
            if (route.meta?.roles) {
                return route.meta.roles.includes(role);
            }
        });
    }
    return false;
};